package com.easyaop.api.advisor;

import com.easyaop.api.Context;
import com.easyaop.api.around.Around;
import com.easyaop.api.pointcut.Pointcut;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public class AroundAdvisor extends Advisor implements Iterable<Around> {
    protected List<Around> arounds = new CopyOnWriteArrayList<>();

    protected AroundAdvisor(Pointcut pointcut) {
        super(pointcut);
    }

    public static AroundAdvisor of(Pointcut pointcut, Around around) {
        AroundAdvisor aroundAdvisor = new AroundAdvisor(pointcut);
        aroundAdvisor.addAround(around);
        return aroundAdvisor;
    }

    public synchronized void addAround(Around around) {
        arounds.add(around);
    }

    public synchronized void registerAround(Around around) {
        arounds.add(around);
        Context.registerAround(signatures, Collections.singleton(around));
    }

    public synchronized void addSignature(String signature) {
        boolean added = signatures.add(signature);
        if (added) {
            Context.registerAround(signature, this);
        }
    }

    public synchronized void removeAround(Class<? extends Around>... aroundTypes) {
        if (aroundTypes == null || aroundTypes.length == 0) {
            Context.removeAround(this, this);
        } else {
            List<Around> list = new ArrayList<>();
            Set<Class<? extends Around>> collect = Stream.of(aroundTypes).collect(Collectors.toSet());
            for (Around around : arounds) {
                if (collect.contains(around.getClass())) {
                    list.add(around);
                }
            }
            Context.removeAround(this, list);
        }
        if (!iterator().hasNext()) {
            Context.removeAdvisor(this);
        }
    }

    @Override
    public Iterator<Around> iterator() {
        return arounds.iterator();
    }
}
